package git.soulbgm.security.service;

import git.soulbgm.common.constant.Constant;
import git.soulbgm.common.enums.Status;
import git.soulbgm.mapper.MenuMapper;
import git.soulbgm.mapper.RoleMapper;
import git.soulbgm.mapper.RoleMenuMapper;
import git.soulbgm.mapper.UserRoleMapper;
import git.soulbgm.pojo.entity.*;
import git.soulbgm.security.config.AuthorityConfig;
import git.soulbgm.security.pojo.LoginUser;
import git.soulbgm.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 权限相关功能
 *
 * @author SoulBGM
 * @date 2020-08-05
 */
@Service("ps")
public class PermissionService {

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private AuthorityConfig config;

    /**
     * 获得用户角色信息
     *
     * @param user 用户
     * @return 角色信息
     */
    public Set<String> getUserRole(User user) {
        Set<String> roleSet = new HashSet<>();
        Example example = new Example(UserRole.class);
        example.and().andEqualTo("userId", user.getId());
        List<UserRole> userRoleList = userRoleMapper.selectByExample(example);
        if (userRoleList.size() > 0) {
            List<Long> roleIdList = new ArrayList<>(userRoleList.size());
            for (UserRole userRole : userRoleList) {
                roleIdList.add(userRole.getRoleId());
            }
            List<Role> roleList = getRoles(roleIdList);
            for (Role role : roleList) {
                roleSet.add(role.getRoleCode());
            }
        }
        return roleSet;
    }

    /**
     * 获得角色信息
     *
     * @param roleIdList 角色id列表
     * @return 角色信息
     */
    private List<Role> getRoles(List<Long> roleIdList) {
        Example roleExample = new Example(Role.class);
        roleExample.and()
                .andIn("id", roleIdList);
        return roleMapper.selectByExample(roleExample);
    }

    /**
     * 获得菜单权限
     *
     * @param user 用户
     * @return 可访问的url
     */
    public Set<String> getMenuPermission(User user) {
        Set<String> permissionSet = new HashSet<>();
        Long userId = user.getId();
        List<Menu> menuList = getUserMenu(userId);
        for (Menu menu : menuList) {
            permissionSet.add(menu.getUrl());
        }
        return permissionSet;
    }

    /**
     * 获取用户菜单
     *
     * @param userId 用户id
     * @return 菜单信息
     */
    public List<Menu> getUserMenu(Long userId) {
        Example example = new Example(UserRole.class);
        example.and().andEqualTo("userId", userId);
        List<UserRole> userRoleList = userRoleMapper.selectByExample(example);
        if (userRoleList.size() > 0) {
            List<Long> roleIdList = new ArrayList<>(userRoleList.size());
            for (UserRole userRole : userRoleList) {
                roleIdList.add(userRole.getRoleId());
            }
            List<Role> roleList = getRoles(roleIdList);
            boolean isAdminRole = false;
            for (Role role : roleList) {
                if ("admin".equals(role.getRoleCode())) {
                    isAdminRole = true;
                    break;
                }
            }

            if (!isAdminRole) {
                Example roleMenuExample = new Example(RoleMenu.class);
                roleMenuExample.and()
                        .andIn("roleId", roleIdList);
                List<RoleMenu> roleMenuList = roleMenuMapper.selectByExample(roleMenuExample);


                List<Long> menuIdList = new ArrayList<>(userRoleList.size());
                for (RoleMenu roleMenu : roleMenuList) {
                    menuIdList.add(roleMenu.getMenuId());
                }

                if (menuIdList.size() > 0) {
                    Example menuExample = new Example(Menu.class);
                    menuExample.and()
                            .andIn("id", menuIdList);
                    return menuMapper.selectByExample(menuExample);
                }
            } else {
                Example menuExample = new Example(Menu.class);
                menuExample.and().andEqualTo("visible", Status.VISIBLE.code);
                return menuMapper.selectByExample(menuExample);
            }
        }
        return Arrays.asList();
    }

    /**
     * 验证用户是否具备某权限
     *
     * @return 用户是否具备某权限
     */
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        String url = request.getRequestURI();
        if (StringUtil.isEmpty(url) || authentication == null) {
            return false;
        }
        Object principal = authentication.getPrincipal();
        // 当未登录时 authentication.getPrincipal=“anonymousUser”
        LoginUser loginUser = null;
        if (principal instanceof LoginUser) {
            loginUser = (LoginUser) principal;
        }
        if (loginUser == null) {
            return false;
        }
        Set<String> permissions = loginUser.getPermissions();
        if (permissions == null) {
            return false;
        }
        return hasPermissions(permissions, url);
    }

    /**
     * 创建一个AntPathMatcher，主要用于实现ant风格的URL匹配
     */
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    /**
     * 判断是否包含权限
     *
     * @param permissions 权限列表
     * @param url         权限字符串
     * @return 用户是否具备某权限
     */
    private boolean hasPermissions(Set<String> permissions, String url) {
        if (config.getFilterAll()) {
            return true;
        }
        for (String permission : permissions) {
            if (antPathMatcher.match(permission, url)) {
                return true;
            }
        }
        return false;
    }


}
